import { c, cartesian, duplicates, shuffle } from '../../utils/arrays'
import { pad } from '../../utils/filters'

const BALLS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

export function stringify (bet) {
  var {bold, content} = bet
  var groups = content.split('*').map(g => g.split('|'))
  var [q, w = []] = groups
  return bold ?
    `<b>(${q.join(' ')}) ${w.join(' ')}</b>` :
    `<b>${groups.map(g => g.join(' ')).join(' | ')}</b>`
}

export function betContent (cart) {
  return cart.map(e => {
    return {
      rule: e.rule,
      bet: e.groups.map(g => g.map(pad).join('|')).join('*')
    }
  })
}

/**
 * 生成投注
 * @param rule 玩法
 */
export function gen (rule) {
  var select = parseInt(rule.substr(1, 1))
  var balls = shuffle(BALLS).slice(-select)
  var groups = []
  switch (rule) {
    case 'q2d':
    case 'q3d':
    case 'l2':
    case 'l3':
      groups = balls.map(b => [b])
      break
    default:
      groups[0] = balls.sort()
  }
  return groups
}

/**
 * 计算中奖盈利
 * @param groups 投注号码分组
 * @param rule   玩法
 * @param bold   是否胆拖玩法
 * @returns {{bonus: number[], bets: number, tips: string}}
 */
export function gain (groups, rule, bold) {

  // 总注数
  var bets = compute(groups, rule, bold)

  if (bets < 1) return {}

  var balls = groups[0],  // 投注(拖码)数组
      bolds = null        // 胆码数组

  if (groups.length == 2) {
    bolds = groups[0]
    balls = groups[1]
  }

  var config = rules[rule],       // 读取玩法配置
      select = rule.substr(1, 1), // 玩法要求选择的数量
      size   = balls.length,      // 选择号码数
      rest   = 11 - size          // 剩余号码数

  var minhits = 1,  // 若中奖，最小中奖注数
      maxhits = 1,  // 若中奖，最大中奖注数
      bonus         // 奖金区间

  switch (rule) {
    case 'q1':  // 前一
    case 'q2d': // 前2直选
    case 'q3d': // 前3直选
    case 'q2c': // 前2组选
    case 'q3c': // 前3组选
      break
    case 'r2':  // 任2至任5
    case 'r3':
    case 'r4':
    case 'r5':
      // 胆拖时
      if (bold) {
        console.log(`c(${Math.min(size, 5 - bolds.length)}, ${select - bolds.length})`)
        maxhits = c(Math.min(size, 5 - bolds.length), select - bolds.length)
        // 剩余球数太小，以致于最小中奖注数可以估计得出
        if (rest - bolds.length <= 5 - select) {
          minhits = c(5 - rest, select - bolds.length)
        }
      }
      // 非胆拖时
      else {
        // 最大注数为 c(Math.min(所选球数，5)，玩法选择数)
        maxhits = c(Math.min(size, 5), select)
        // 剩余球数太小，以致于最小中奖注数可以估计得出
        if (5 - rest >= select) {
          minhits = c(5 - rest, select)
        }
      }
      break
    case 'r6':  // 任6至任8
    case 'r7':
    case 'r8':
      // 胆拖时
      if (bold) {
        // 玩法选择数 超过7个时
        if (select - bolds.length > 5) {
          minhits = c(size - 5, select - 5 - bolds.length)
        } else {
          minhits = 1
        }

        // 胆码数多于已选球数
        if (bolds.length > size) {
          maxhits = c(size, select - bolds.length)
        } else {
          maxhits = c(size + bolds.length - 5, select - 5)
        }
      }
      // 非胆拖时
      else {
        if (size > select) {
          maxhits = c(size - 5, select - 5)
          minhits = maxhits
        }
      }
      break
    case 'l2':  // 乐2至乐5
      bonus = [6, 6 + 65 + 130] // 任选二，前二组选，前二直选
      break
    case 'l3':
      bonus = [19, 19 + 195 + 1170] // 任选三，前选组选，前选直选
      break
    case 'l4':
      bonus = [6, 19 * 4 + 78] // 任选选x3，任选四x1
      break
    case 'l5':
      bonus = [540 + 90 * 6, 540 + 90 * 6] // 任选五x1, 任选六x6
      break
  }

  if (rule.substr(0, 1) != 'l') {
    // 奖金区间
    bonus = [config.bonus * minhits, config.bonus * maxhits]
  }
  // 盈利区间
  var gains = [bonus[0] - bets * 2, bonus[1] - bets * 2]

  var tips = gaintips(bonus, gains)

  return {groups, bonus, bets, tips}
}

/**
 * 生成盈利说明
 * @param bonus 奖金区间
 * @param gains 盈利区间
 * @returns {string} 说明字符串
 */
function gaintips (bonus, gains) {
  var tips = `若中奖，奖金<b>${bonus[0]}</b>`
  if (bonus.length > 1 && bonus[0] != bonus[1]) {
    tips += `至<b>${bonus[1]}</b>`
  }
  tips += '元，'

  if (gains.length == 1 || gains[0] == gains[1]) {
    tips += gains[0] >= 0 ?
      `盈利<b>${gains[0]}</b>` :
      `亏损<i>${-gains[0]}</i>`
  } else {
    if (gains[1] > 0) {
      tips += `盈利${tag(gains[0])}至<b>${gains[1]}</b>`
    } else if (gains[0] <= 0) {
      tips += `亏损<i>${-gains[0]}</i>至<i>${-gains[1]}</i>`
    }
  }
  tips += '元'
  return tips
}

function tag (n) {
  return n > 0 ? `<b>${n}</b>` : `<i>${n}</i>`
}

/**
 * 计算注数, 奖金与盈利, 并检查投注格式
 *
 * @param groups  投注内容二维数组
 * @param rule    玩法
 * @param bold    是否胆拖投注
 * @return number 总注数
 */
export function compute (groups, rule, bold) {

  var bets  = groups[0],  // 投注(拖码)数组
      bolds = null        // 胆码数组

  if (groups.length == 2) {
    bolds = groups[0]
    bets = groups[1]
  }

  // 玩法要求选择的数量
  var select = rule.substr(1, 1)
  switch (rule) {
    case 'q1':  // 前一
      return bets.length
    case 'q2d': // 前2直选
    case 'q3d': // 前3直选
      if (groups.length != select) {
        return 0
      }
      return cartesian_count(groups)
    case 'q2c': // 前2组选
    case 'q3c': // 前3组选
    case 'r2':  // 任2至任8
    case 'r3':
    case 'r4':
    case 'r5':
    case 'r6':
    case 'r7':
    case 'r8':
      // 设胆时, 求拖码组合
      if (bold) {
        if (bolds == null || bolds.length < 1) return 0
        if (bolds.length >= select) throw new Error('胆码数不能超过玩法单注选择数.')
        if (duplicates(bolds, bets)) throw new Error('胆码与拖码包含重复数字.')
        return c(bets.length, select - bolds.length)
      }
      // 未设胆时, 直接求Cm-n
      else {
        return c(bets.length, select)
      }
    case 'l2':  // 乐2至乐5
      return groups.length == 2 ? 3 : 0
    case 'l3':
      return groups.length == 3 ? 3 : 0
    case 'l4':
      return bets.length == 4 ? 4 : 0
    case 'l5':
      return bets.length == 5 ? 7 : 0
  }
}

function cartesian_count (groups) {
  var len = 0
  cartesian(groups, function (arr) {
    len += duplicates(arr) ? 0 : 1
  })
  return len
}

// 玩法配置
export const rules = {
  q1: {
    name: '前一',
    groups: ['万位'],
    balls: 1, // 选择球数
    bonus: 13,
    tips () { return `至少选择${this.balls}个，猜对第1个开奖号码即中<b>${this.bonus}</b>元` }
  },
  q2c: {
    name: '前二组选',
    groups: ['选号'],
    balls: 2,
    bonus: 65,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1</b>个胆码，1个或以上的拖码，胆码+拖码≥2个，猜中前2个开奖号中<b>${this.bonus}</b>元` :
        `每位至少选择${this.balls}个，按位猜对开奖号码前2位即中<b>${this.bonus}</b>元`
    }
  },
  q2d: {
    name: '前二直选',
    groups: ['万位', '千位'],
    balls: 1,
    bonus: 130,
    tips () { return `每位至少选择${this.balls}个，按位猜对开奖号码前2位即中<b>${this.bonus}</b>元`}
  },
  q3c: {
    name: '前三组选',
    groups: ['选号'],
    balls: 3,
    bonus: 195,
    tips (bold) {
      return bold ?
        `选择<b>1</b>或<b>2</b>个胆码，1个或以上的拖码，胆码+拖码≥3个，猜中前3个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对前3个开奖号码即中<b>${this.bonus}</b>元`

    }
  },
  q3d: {
    name: '前三直选',
    groups: ['万位', '千位', '百位'],
    balls: 1,
    bonus: 1170,
    tips () { return `每位至少选择${this.balls}个，按位猜对开奖号码前3位即中<b>${this.bonus}</b>元`}
  },
  r2: {
    name: '任选二',
    groups: ['选号'],
    balls: 2,
    bonus: 6,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1</b>个胆码，1个或以上的拖码，胆码+拖码≥2个，猜中2个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对任意${this.balls}个开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  r3: {
    name: '任选三',
    groups: ['选号'],
    balls: 3,
    bonus: 19,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1~2</b>个胆码，1个以上的拖码，胆码+拖码≥3个，猜中3个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对任意${this.balls}个开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  r4: {
    name: '任选四',
    groups: ['选号'],
    balls: 4,
    bonus: 78,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1~3</b>个胆码，1个以上的拖码，胆码+拖码≥4个，猜中4个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对任意${this.balls}个开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  r5: {
    name: '任选五',
    groups: ['选号'],
    balls: 5,
    bonus: 540,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1~4</b>个胆码，1个或以上的拖码，胆码+拖码≥5个，猜中5个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对全部开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  r6: {
    name: '任选六',
    groups: ['选号'],
    balls: 6,
    bonus: 90,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1~5</b>个胆码，1个或以上的拖码，胆码+拖码≥6个，猜中5个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对全部开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  r7: {
    name: '任选七',
    groups: ['选号'],
    balls: 7,
    bonus: 26,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1~6</b>个胆码，1个或以上的拖码，胆码+拖码≥7个，猜中5个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对全部开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  r8: {
    name: '任选八',
    groups: ['选号'],
    balls: 8,
    bonus: 9,
    bold: true,
    tips (bold) {
      return bold ?
        `选择<b>1~7</b>个胆码，1个或以上的拖码，胆码+拖码≥8个，猜中5个开奖号中<b>${this.bonus}</b>元` :
        `至少选择${this.balls}个，猜对全部开奖号码即中<b>${this.bonus}</b>元`
    }
  },
  l2: {
    name: '乐选二',
    groups: ['万位', '千位'],
    conflict: true,
    balls: 1,
    max: 1,
    tips () { return `每位选择${this.balls}个，组成1注前二直选、前二组选及任选二`}
  },
  l3: {
    name: '乐选三',
    groups: ['万位', '千位', '百位'],
    conflict: true,
    balls: 1,
    max: 1,
    tips () { return `每位选择${this.balls}个，组成1注前三直选、前三组选及任选三`}
  },
  l4: {
    name: '乐选四',
    groups: ['选号'],
    balls: 4,
    max: 4,
    tips () { return `选择${this.balls}个，组成4注任选三，1注任选四`}
  },
  l5: {
    name: '乐选五',
    groups: ['选号'],
    balls: 5,
    max: 5,
    tips () { return `选择${this.balls}个，组成6注任选六，1注任选五`}
  }
}
